#ifndef __MATH_OP_H__
#define __MATH_OP_H__
#include <iostream>
#include "math/math_config.h"

NS_MATH_BEGIN

#define OP1(OP) \
	this_type& operator OP (const_reference val) \
	{ \
		for(size_type i=0;i<size();++i){m_data[i] OP val;} \
		return *this; \
	} \
	this_type& operator OP (const this_type& a) \
	{ \
		for(size_type i=0;i<size();++i){m_data[i] OP a.m_data[i];} \
		return *this; \
	}

// for POD type
#define OP2(OP, OP1) \
	this_type operator OP (const_reference val) \
	{ \
		this_type tmp(*this); \
		tmp OP1 val; \
		return std::move(tmp); \
	} \
	this_type operator OP (const this_type& a) \
	{ \
		this_type tmp(*this); \
		tmp OP1 a; \
		return std::move(tmp); \
	}

// Accumulated Operators Class

template<typename T>
class aop_sum
{
protected:
	T _sum;
public:
	aop_sum():_sum(T()){}

	inline void g(T& val)
	{
		_sum += val;
	}

	void reset(){_sum=T();}

	operator T () const
	{
		return _sum;
	}
};


template<typename T>
class aop_min
{
protected:
	T _min;
	bool started;
public:
	aop_min():started(false){}

	inline void g(T& val)
	{
		if(!started)
		{
			_min = val;
			started = true;
		}else
		{
			_min = std::min(_min,val);
		}
	}
	operator T () const
	{
		return _min;
	}

	void reset()
	{
		started = false;
	}
};

template<typename T>
class aop_max
{
protected:
	T _max;
	bool started;
public:
	aop_max():started(false){}

	inline void g(T& val)
	{
		if(!started)
		{
			_max = val;
			started = true;
		}else
		{
			_max = std::max(_max, val);
		}
	}
	operator T () const
	{
		return _max;
	}

	void reset()
	{
		started = false;
	}
};

template<typename T>
class aop_minmax
{
protected:
	aop_min<T> _min;
	aop_max<T> _max;

public:
	aop_minmax():_min(),_max(){}

	inline void g(T& val)
	{
		_min.g(val);
		_max.g(val);
	}

	T min(){return _min;}
	T max(){return _max;}

	void reset()
	{
		_min.reset();
		_max.reset();
	}
};

template<typename T>
class aop_mean
{
protected:
	T _sum;
	size_t count;
public:
	aop_mean():_sum(T()),count(0){}

	inline void g(T& val)
	{
		_sum += val;
	}

	operator T () const
	{
		return _sum/count;
	}

	void reset()
	{
		_sum = T();
		count = 0;
	}
};

template<typename T>
class aop_set
{
public:
	typedef aop_set<T> this_type;
protected:
	T _val;

	aop_set(const T& val = T()):_val(val){}

	inline void g(T& val)
	{
		val = _val;
	}

	operator T& ()
	{
		return _val;
	}

	operator const T& () const
	{
		return _val;
	}

	this_type& operator= (const T& val)
	{
		_val = val;
		return *this;
	}

	void reset()
	{
		_val = T();
	}
};

template<typename T>
class aop_mul
{
public:
	typedef aop_mul<T> this_type;
protected:
	T _factor;

public:
	inline void g(T& val)
	{
		val *= _factor;
	}
	operator T& ()
	{
		return _factor;
	}
	operator const T& () const
	{
		return _factor;
	}

	this_type& operator= (const T& val)
	{
		_factor = val;
		return *this;
	}

	void reset()
	{
		_factor = T();
	}
};

template<typename T>
class aop_range
{
public:
	typedef aop_range<T> this_type;

	T count;

public:
	aop_range(const T& start = T()):count(start){}

public:
	inline void g(T& val)
	{
		val = count;
		count++;
	}
};

NS_MATH_END

#endif